//
// Created on 2025/11/20.
// Author 秦光磊.
#include <GLES3/gl3.h>
#include <vector>
#include <hilog/log.h>
#include "gencoordinate/gen_coordinate.h"
#include "constant/constant.h"
/**
 * 若需要根据两点绘制一条虚线，这里生成两点间虚线上的点
 * @param fromVertices 起始点
 * @param fromSize 起始点数值数，一般是3
 * @param toVertices 结尾点
 * @param toSize 结尾点，一般是3
 * @param geometryAttribute 何参数中用到geometryAttribute[1]，其它随意。geometryAttribute[1]为1表示画小图，为2表示画大图
 * @param attrSize 几何参数大小，因为要用到geometryAttribute[1]，所以大小至少是2个
 * @return 返回两点连线上的虚线点坐标
 */
std::vector<GLfloat> GenCoordinate::GenDottedStraightLineCoordinate(std::vector<GLfloat> &fromVertices, int fromSize,
                                                                    std::vector<GLfloat> &toVertices, int toSize,
                                                                    int *geometryAttribute, int attrSize) {

    OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_PRINT_DOMAIN, "GenCoordinate", "%{public}s start.", __func__);
    // 顶点坐标，这里准备存储一条线上的点
    std::vector<GLfloat> dottedCoordinates;
    if ((fromSize < 3) || (toSize < 3) || (attrSize < 2)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GenCoordinate",
                     "%{public}s 参数检查不对。fromSize:%{public}d,toSize:%{public}d,attrSize:%{public}d.", __func__,
                     fromSize, toSize, attrSize);
        return dottedCoordinates;
    }
    if (fromVertices.size() < fromSize) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GenCoordinate",
                     "%{public}s fromVertices大小不对。fromVertices.size():%zu.", __func__, fromVertices.size());
        return dottedCoordinates;
    }
    if (toVertices.size() < toSize) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GenCoordinate",
                     "%{public}s toVertices大小不对。toVertices.size():%zu.", __func__, toVertices.size());
        return dottedCoordinates;
    }
    if (geometryAttribute == nullptr) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GenCoordinate", "%{public}s geometryAttribute为nullptr.",
                     __func__);
        return dottedCoordinates;
    }

    // 虚线上一点的x坐标
    float x;
    // 虚线上一点的y坐标
    float y;
    // 虚线上一点的z坐标
    float z;
    // 为方便计算，头尾坐标拆开处理
    float fromPoint_X = fromVertices[0];
    float fromPoint_Y = fromVertices[1];
    float fromPoint_Z = fromVertices[2];
    float toPoint_X = toVertices[0];
    float toPoint_Y = toVertices[1];
    float toPoint_Z = toVertices[2];
    // 两点在x轴方向的跨度，注意这里需要取正数
    float distanceX;
    // 两点在y轴方向的跨度，注意这里需要取正数
    float distanceY;
    // 两点在z轴方向的跨度，注意这里需要取正数
    float distanceZ;
    distanceX = std::fabsf((fromPoint_X - toPoint_X));
    distanceY = std::fabsf((fromPoint_Y - toPoint_Y));
    distanceZ = std::fabsf((fromPoint_Z - toPoint_Z));
    if ((distanceX == 0) && (distanceY == 0) && (distanceZ == 0)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GenCoordinate", "%{public}s error。因为两点重合.",
                     __func__);
        return dottedCoordinates;
    }

    // 两点之前，分别有在x,y,z轴方向的间距，这里准备获取轴向最大的间距.
    //  例如点（0,0,0）与点(1,2,3),x轴方向的间距是1，y轴防线的间距是2，z轴方向的间距是3，那么这里将取值3
    float maxDistance;
    maxDistance = std::max(std::max(distanceX, distanceY), distanceZ);

    // 两点间分割数，设置默认值，长线分割数多，适用于大图，反之，短线分割数小，适用于小图
    int blocks = 10;
    // 表示画小图，采集点数少，设置为20
    if (geometryAttribute[1] == 1)
        blocks = 20;
    // 表示画大图，采集点数多，设置为100
    if (geometryAttribute[1] == 2)
        blocks = 100;
    // 通过块数计算出步长
    float step = maxDistance / blocks;

    if (maxDistance == distanceX) {
        // x轴最大，则以x轴为分割方向，分割线段成虚线，两点构成一线，取该线上部分点绘制，这样就能绘制虚线
        // 根据公式 (x - X1) / (X2 - X1) = (y - Y1) / (Y2 - Y1) = (z - Z1) / (Z2 - Z1)
        // 此时若固定x，则y = (x - X1) * (Y2 - Y1) / (X2 - X1) + Y1
        // 此时若固定x，则z = (x - X1) * (Z2 - Z1) / (X2 - X1) + Z1
        if (fromPoint_X <= toPoint_X) {
            for (x = fromPoint_X; x <= toPoint_X; x = x + step) {
                y = ((x - fromPoint_X) * (toPoint_Y - fromPoint_Y) / (toPoint_X - fromPoint_X)) + fromPoint_Y;
                z = ((x - fromPoint_X) * (toPoint_Z - fromPoint_Z) / (toPoint_X - fromPoint_X)) + fromPoint_Z;
                dottedCoordinates.push_back(x);
                dottedCoordinates.push_back(y);
                dottedCoordinates.push_back(z);
            }
        } else {
            for (x = fromPoint_X; x >= toPoint_X; x = x - step) {
                y = ((x - fromPoint_X) * (toPoint_Y - fromPoint_Y) / (toPoint_X - fromPoint_X)) + fromPoint_Y;
                z = ((x - fromPoint_X) * (toPoint_Z - fromPoint_Z) / (toPoint_X - fromPoint_X)) + fromPoint_Z;
                dottedCoordinates.push_back(x);
                dottedCoordinates.push_back(y);
                dottedCoordinates.push_back(z);
            }
        }
    } else if (maxDistance == distanceY) {
        // y轴最大，则以y轴为分割方向，分割线段成虚线，两点构成一线，取该线上部分点绘制，这样就能绘制虚线
        // 根据公式 (x - X1) / (X2 - X1) = (y - Y1) / (Y2 - Y1) = (z - Z1) / (Z2 - Z1)
        // 此时若固定y，则x = (y - Y1) * (X2 - X1) / (Y2 - Y1) + X1
        // 此时若固定y，则z = (y - Y1) * (Z2 - Z1) / (Y2 - Y1) + Z1
        if (fromPoint_Y <= toPoint_Y) {
            for (y = fromPoint_Y; y <= toPoint_Y; y = y + step) {
                x = ((y - fromPoint_Y) * (toPoint_X - fromPoint_X) / (toPoint_Y - fromPoint_Y)) + fromPoint_X;
                z = ((y - fromPoint_Y) * (toPoint_Z - fromPoint_Z) / (toPoint_Y - fromPoint_Y)) + fromPoint_Z;
                dottedCoordinates.push_back(x);
                dottedCoordinates.push_back(y);
                dottedCoordinates.push_back(z);
            }
        } else {
            for (y = fromPoint_Y; y >= toPoint_Y; y = y - step) {
                x = ((y - fromPoint_Y) * (toPoint_X - fromPoint_X) / (toPoint_Y - fromPoint_Y)) + fromPoint_X;
                z = ((y - fromPoint_Y) * (toPoint_Z - fromPoint_Z) / (toPoint_Y - fromPoint_Y)) + fromPoint_Z;
                dottedCoordinates.push_back(x);
                dottedCoordinates.push_back(y);
                dottedCoordinates.push_back(z);
            }
        }
    } else {
        // z轴最大，则以z轴为分割方向，分割线段成虚线，两点构成一线，取该线上部分点绘制，这样就能绘制虚线
        // 根据公式 (x - X1) / (X2 - X1) = (y - Y1) / (Y2 - Y1) = (z - Z1) / (Z2 - Z1)
        // 此时若固定z，则x = (z - Z1) * (X2 - X1) / (Z2 - Z1) + X1
        // 此时若固定z，则y = (z - Z1) * (Y2 - Y1) / (Z2 - Z1) + Y1
        if (fromPoint_Z <= toPoint_Z) {
            for (z = fromPoint_Z; z <= toPoint_Z; z = z + step) {
                x = ((z - fromPoint_Z) * (toPoint_X - fromPoint_X) / (toPoint_Z - fromPoint_Z)) + fromPoint_X;
                y = ((z - fromPoint_Z) * (toPoint_Y - fromPoint_Y) / (toPoint_Z - fromPoint_Z)) + fromPoint_Y;
                dottedCoordinates.push_back(x);
                dottedCoordinates.push_back(y);
                dottedCoordinates.push_back(z);
            }
        } else {
            for (z = fromPoint_Z; z >= toPoint_Z; z = z - step) {
                x = ((z - fromPoint_Z) * (toPoint_X - fromPoint_X) / (toPoint_Z - fromPoint_Z)) + fromPoint_X;
                y = ((z - fromPoint_Z) * (toPoint_Y - fromPoint_Y) / (toPoint_Z - fromPoint_Z)) + fromPoint_Y;
                dottedCoordinates.push_back(x);
                dottedCoordinates.push_back(y);
                dottedCoordinates.push_back(z);
            }
        }
    }
    // 返回虚线上点坐标
    return dottedCoordinates;
}
/**
 * 产生XOY平面上的椭圆（弧）坐标清单
 * 从Y轴正方向往X轴正方向的角度为startAngle，arcAngle为增量角度就是弧度
 * startAngle = 0 与 arcAngle = 360度则会画一个椭圆，否则会画一个椭圆的一部分弧，
 * 按照x^2/a^2 + y^2/b^2 =1来确定椭圆坐标
 * @param a
 * @param b
 * @param centerVertices 椭圆中心坐标，因为这里的弧度是椭圆弧度
 * @param centerSize 中心坐标上数值个数，一般是3
 * @param startAngle 弧度开始角度，为以Y轴正方向为起点，顺时针的角度
 * @param arcAngle  增量角度就是弧度
 * @param geometryAttribute
 * 几何参数中用到geometryAttribute[1]，其它随意。geometryAttribute[1]为1表示画小图，为2表示画大图
 * @param attrSize 几何参数大小，因为要用到geometryAttribute[1]，所以大小至少是2个
 * @return 产生XOY平面上的椭圆（弧）坐标清单
 */
std::vector<GLfloat> GenCoordinate::GenOneEllipseArcCoordinates(float a, float b, std::vector<GLfloat> &centerVertices,
                                                                int centerSize, float startAngle, float arcAngle,
                                                                int *geometryAttribute, int attrSize) {
    OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_PRINT_DOMAIN, "GenCoordinate", "%{public}s start.", __func__);
    // 返回的弧度坐标
    std::vector<GLfloat> arcCoordinates;
    if ((centerSize < 3) || (attrSize < 2)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GenCoordinate",
                     "%{public}s param error.centerSize:%{public}d,attrSize:%{public}d.", __func__, centerSize,
                     attrSize);
        return arcCoordinates;
    }
    if (centerVertices.size() < centerSize) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GenCoordinate",
                     "%{public}s centerVertices大小不对。centerVertices.size():%zu.", __func__, centerVertices.size());
        return arcCoordinates;
    }
    if (geometryAttribute == nullptr) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GenCoordinate", "%{public}s geometryAttribute为nullptr.",
                     __func__);
        return arcCoordinates;
    }
    OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_PRINT_DOMAIN, "GenCoordinate", "%{public}s 参数值a：%{public}f,b:%{public}f.",
                 __func__, a, b);
    if ((a <= 0) || (b <= 0)) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "GenCoordinate", "%{public}s a与b不能为0.", __func__);
        return arcCoordinates;
    }
    // 先拆开中心坐标，便于代码编码
    GLfloat centerX = centerVertices[0];
    GLfloat centerY = centerVertices[1];
    GLfloat centerZ = centerVertices[2];
    OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_PRINT_DOMAIN, "GenCoordinate",
                 "%{public}s centerVertices坐标参数值x：%{public}f,y:%{public}f,z:%{public}f.", __func__, centerX,
                 centerY, centerY);
    // 椭圆上取点坐标
    float orbitX;
    float orbitY;
    float orbitZ;
    // 取点间隔,设置默认值，该值看最终效果展示来调整，在不失真的条件下，尽可能大，这样采集的点的数量就尽可能少,降低资源消耗
    float collectSpan = 0.4f;
    // 1表示绘制小图，点阵间隔0.5，那么采集的点就相对小些,默认画小图，点阵间隔大
    if (geometryAttribute[1] == 1)
        collectSpan = 0.5f;
    // 2表示绘制大图，点阵间隔0.2，那么采集的点就相对大些
    if (geometryAttribute[1] == 2)
        collectSpan = 0.1f;
    OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_PRINT_DOMAIN, "GenCoordinate",
                 "%{public}s 起始角度startAngle：%{public}f,增量角度arcAngle:%{public}f.", __func__, startAngle,
                 arcAngle);

    // 获取从startAngle到startAngle + arcAngle之间的坐标，
    // 区间为[startAngle,startAngle + arcAngle),因为无法保证最后一个点一定会取到
    for (float alpha = startAngle; alpha < startAngle + arcAngle; alpha = alpha + collectSpan) {
        // XOY平面的椭圆
        orbitX = (float)(sin(alpha) * a) + centerX;
        orbitY = (float)(cos(alpha) * b) + centerY;
        orbitZ = centerZ;
        // 添加坐标
        arcCoordinates.push_back(orbitX);
        arcCoordinates.push_back(orbitY);
        arcCoordinates.push_back(orbitZ);
        OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_PRINT_DOMAIN, "GenCoordinate",
                     "%{public}s 添加一坐标,x：%{public}f,y:%{public}f,z:%{public}f.", __func__, orbitX, orbitY,
                     orbitZ);
    }

    // 在获取区间为[startAngle,startAngle + arcAngle)的点后，
    // 将最后一个startAngle +arcAngle角度对应的点添加到返回的点阵上
    float lastOrbitX = (float)(sin(startAngle + arcAngle) * a) + centerY;
    float lastOrbitY = (float)(cos(startAngle + arcAngle) * b) + centerZ;
    // 添加最后一个坐标
    arcCoordinates.push_back(lastOrbitX);
    arcCoordinates.push_back(lastOrbitY);
    arcCoordinates.push_back(centerZ);
    OH_LOG_Print(LOG_APP, LOG_DEBUG, LOG_PRINT_DOMAIN, "GenCoordinate",
                 "%{public}s 添加最后一个坐标,x：%{public}f,y:%{public}f,z:%{public}f.", __func__, orbitX, orbitY,
                 orbitZ);
    // 返回坐标
    return arcCoordinates;
}
